home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / Text / Show / Less / less-252 / cmdbuf.c < prev    next >
C/C++ Source or Header  |  1994-10-25  |  18KB  |  940 lines

  1. /*
  2.  * Copyright (c) 1984,1985,1989,1994  Mark Nudelman
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice in the documentation and/or other materials provided with 
  12.  *    the distribution.
  13.  *
  14.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
  15.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  17.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
  18.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  19.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
  20.  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
  21.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  22.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
  23.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 
  24.  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.  */
  26.  
  27.  
  28. /*
  29.  * Functions which manipulate the command buffer.
  30.  * Used only by command() and related functions.
  31.  */
  32.  
  33. #include "less.h"
  34. #include "cmd.h"
  35.  
  36. extern int sc_width;
  37.  
  38. static char cmdbuf[120];    /* Buffer for holding a multi-char command */
  39. static int cmd_col;        /* Current column of the multi-char command */
  40. static char *cp;        /* Pointer into cmdbuf */
  41. static int literal;
  42.  
  43. #if TAB_COMPLETE_FILENAME
  44. static int cmd_complete();
  45. /*
  46.  * These variables are statics used by cmd_complete.
  47.  */
  48. static int in_completion = 0;
  49. static char *tk_text;
  50. static char *tk_original;
  51. static char *tk_ipoint;
  52. static char *tk_trial;
  53. static struct textlist tk_tlist;
  54. #endif
  55.  
  56. #if CMD_HISTORY
  57. /*
  58.  * A mlist structure represents a command history.
  59.  */
  60. struct mlist
  61. {
  62.     struct mlist *next;
  63.     struct mlist *prev;
  64.     struct mlist *curr_mp;
  65.     char *string;
  66. };
  67.  
  68. /*
  69.  * These are the various command histories that exist.
  70.  */
  71. struct mlist mlist_search =  
  72.     { &mlist_search,  &mlist_search,  &mlist_search,  NULL };
  73. public void *ml_search = (void *) &mlist_search;
  74. struct mlist mlist_examine = 
  75.     { &mlist_examine, &mlist_examine, &mlist_examine, NULL };
  76. public void *ml_examine = (void *) &mlist_examine;
  77. #if SHELL_ESCAPE || PIPEC
  78. struct mlist mlist_shell =   
  79.     { &mlist_shell,   &mlist_shell,   &mlist_shell,   NULL };
  80. public void *ml_shell = (void *) &mlist_shell;
  81. #endif /* SHELL_ESCAPE || PIPEC */
  82.  
  83. /*
  84.  * History for the current command.
  85.  */
  86. static struct mlist *curr_mlist = NULL;
  87.  
  88. #endif /* CMD_HISTORY */
  89.  
  90. /*
  91.  * Reset command buffer (to empty).
  92.  */
  93.     public void
  94. cmd_reset()
  95. {
  96.     cp = cmdbuf;
  97.     *cp = '\0';
  98.     cmd_col = 0;
  99.     literal = 0;
  100. }
  101.  
  102. /*
  103.  * How many characters are in the command buffer?
  104.  */
  105.     public int
  106. len_cmdbuf()
  107. {
  108.     return (strlen(cmdbuf));
  109. }
  110.  
  111. /*
  112.  * Backspace in the command buffer.
  113.  * Delete the char to the left of the cursor.
  114.  */
  115.     static int
  116. cmd_erase()
  117. {
  118.     register char *s;
  119.     char *p;
  120.     int col;
  121.  
  122.     if (cp == cmdbuf)
  123.     {
  124.         /*
  125.          * Backspace past beginning of the buffer:
  126.          * this usually means abort the command.
  127.          */
  128.         return (CC_QUIT);
  129.     }
  130.     /*
  131.      * Back up the pointer.
  132.      */
  133.     --cp;
  134.     /*
  135.      * Remember the current cursor column and 
  136.      * set it back the width of the char being erased.
  137.      */
  138.     col = cmd_col;
  139.     p = prchar(*cp);
  140.     cmd_col -= strlen(p);
  141.     /*
  142.      * Shift left the buffer after the erased char.
  143.      */
  144.     for (s = cp;  *s != '\0';  s++)
  145.         s[0] = s[1];
  146.     /*
  147.      * Back up the cursor to the position of the erased char,
  148.      * clear the tail of the line,
  149.      * and reprint the line after the erased char.
  150.      */
  151.     while (col > cmd_col)
  152.     {
  153.         putbs();
  154.         col--;
  155.     }
  156.     clear_eol();
  157.     for (s = cp;  *s != '\0';  s++)
  158.     {
  159.         p = prchar(*s);
  160.         putstr(p);
  161.         col += strlen(p);
  162.     }
  163.     /*
  164.      * Back up the cursor again.
  165.      */
  166.     while (col > cmd_col)
  167.     {
  168.         putbs();
  169.         col--;
  170.     }
  171.     
  172.     /*
  173.      * This is rather weird.
  174.      * We say that erasing the entire command string causes us
  175.      * to abort the current command, BUT ONLY IF there is no history
  176.      * for this type of command.  This causes commands like search (/)
  177.      * and edit (:e) to stay active even if we erase the entire string,
  178.      * but commands like <digit> and - go away when we erase the string.
  179.      * (See same thing in cmd_kill.)
  180.      */
  181.     if (curr_mlist == NULL && cp == cmdbuf && *cp == '\0')
  182.         return (CC_QUIT);
  183.     return (CC_OK);
  184. }
  185.  
  186. /*
  187.  * Delete the char under the cursor.
  188.  */
  189.     static int
  190. cmd_delete()
  191. {
  192.     char *p;
  193.     
  194.     if (*cp == '\0')
  195.     {
  196.         /*
  197.          * At end of string; there is no char under the cursor.
  198.          */
  199.         return (CC_OK);
  200.     }
  201.     /*
  202.      * Move right, then use cmd_erase.
  203.      */
  204.     p = prchar(*cp);
  205.     cp++;
  206.     putstr(p);
  207.     cmd_col += strlen(p);
  208.     cmd_erase();
  209.     return (CC_OK);
  210. }
  211.  
  212. /*
  213.  * Delete the "word" to the left of the cursor.
  214.  */
  215.     static int
  216. cmd_werase()
  217. {
  218.     if (cp > cmdbuf && cp[-1] == ' ')
  219.     {
  220.         /*
  221.          * If the char left of cursor is a space,
  222.          * erase all the spaces left of cursor (to the first non-space).
  223.          */
  224.         while (cp > cmdbuf && cp[-1] == ' ')
  225.             (void) cmd_erase();
  226.     } else
  227.     {
  228.         /*
  229.          * If the char left of cursor is not a space,
  230.          * erase all the nonspaces left of cursor (the whole "word").
  231.          */
  232.         while (cp > cmdbuf && cp[-1] != ' ')
  233.             (void) cmd_erase();
  234.     }
  235.     return (CC_OK);
  236. }
  237.  
  238. /*
  239.  * Delete the "word" under the cursor.
  240.  */
  241.     static int
  242. cmd_wdelete()
  243. {
  244.     if (*cp == ' ')
  245.     {
  246.         /*
  247.          * If the char under the cursor is a space,
  248.          * delete it and all the spaces right of cursor.
  249.          */
  250.         while (*cp == ' ')
  251.             (void) cmd_delete();
  252.     } else
  253.     {
  254.         /*
  255.          * If the char under the cursor is not a space,
  256.          * delete it and all nonspaces right of cursor (the whole word).
  257.          */
  258.         while (*cp != ' ' && *cp != '\0')
  259.             (void) cmd_delete();
  260.     }
  261.     return (CC_OK);
  262. }
  263.  
  264. /*
  265.  * Move cursor to start of command buffer.
  266.  */
  267.     static int
  268. cmd_home()
  269. {
  270.     char *p;
  271.     
  272.     /*
  273.      * Back up until we hit start of buffer.
  274.      */
  275.     while (cp > cmdbuf)
  276.     {
  277.         cp--;
  278.         p = prchar(*cp);
  279.         cmd_col -= strlen(p);
  280.         while (*p++ != '\0')
  281.             putbs();
  282.     }
  283.     return (CC_OK);
  284. }
  285.  
  286. /*
  287.  * Delete all chars in the command buffer.
  288.  */
  289.     static int
  290. cmd_kill()
  291. {
  292.     if (cmdbuf[0] == '\0')
  293.     {
  294.         /*
  295.          * Buffer is already empty; abort the current command.
  296.          */
  297.         return (CC_QUIT);
  298.     }
  299.     (void) cmd_home();
  300.     *cp = '\0';
  301.     clear_eol();
  302.     /*
  303.      * Same weirdness as in cmd_erase.
  304.      * If the current command has no history, abort the current command.
  305.      */
  306.     if (curr_mlist == NULL)
  307.         return (CC_QUIT);
  308.     return (CC_OK);
  309. }
  310.  
  311. /*
  312.  * Move cursor right one character.
  313.  */
  314.     static int
  315. cmd_right()
  316. {
  317.     char *p;
  318.     
  319.     if (*cp == '\0')
  320.     {
  321.         /* 
  322.          * Already at the end of the line.
  323.          */
  324.         return (CC_OK);
  325.     }
  326.     p = prchar(*cp);
  327.     cp++;
  328.     putstr(p);
  329.     cmd_col += strlen(p);
  330.     return (CC_OK);
  331. }
  332.  
  333. /*
  334.  * Move cursor left one character.
  335.  */
  336.     static int
  337. cmd_left()
  338. {
  339.     char *p;
  340.     
  341.     if (cp <= cmdbuf)
  342.     {
  343.         /* Already at the beginning of the line */
  344.         return (CC_OK);
  345.     }
  346.     cp--;
  347.     p = prchar(*cp);
  348.     cmd_col -= strlen(p);
  349.     while (*p++ != '\0')
  350.         putbs();
  351.     return (CC_OK);
  352. }
  353.  
  354. #if CMD_HISTORY
  355. /*
  356.  * Select an mlist structure to be the current command history.
  357.  */
  358.     public void
  359. set_mlist(mlist)
  360.     void *mlist;
  361. {
  362.     curr_mlist = (struct mlist *) mlist;
  363. }
  364.  
  365. /*
  366.  * Move up or down in the currently selected command history list.
  367.  */
  368.     static int
  369. cmd_updown(action)
  370.     int action;
  371. {
  372.     char *p;
  373.     char *s;
  374.     
  375.     if (curr_mlist == NULL)
  376.     {
  377.         /*
  378.          * The current command has no history list.
  379.          */
  380.         bell();
  381.         return (CC_OK);
  382.     }
  383.     cmd_home();
  384.     clear_eol();
  385.     /*
  386.      * Move curr_mp to the next/prev entry.
  387.      */
  388.     if (action == EC_UP)
  389.         curr_mlist->curr_mp = curr_mlist->curr_mp->prev;
  390.     else
  391.         curr_mlist->curr_mp = curr_mlist->curr_mp->next;
  392.     /*
  393.      * Copy the entry into cmdbuf and echo it on the screen.
  394.      */
  395.     s = curr_mlist->curr_mp->string;
  396.     if (s == NULL)
  397.         s = "";
  398.     for (cp = cmdbuf;  *s != '\0';  s++, cp++)
  399.     {
  400.         *cp = *s;
  401.         p = prchar(*cp);
  402.         cmd_col += strlen(p);
  403.         putstr(p);
  404.     }
  405.     *cp = '\0';
  406.     return (CC_OK);
  407. }
  408.  
  409. /*
  410.  * Accept the command in the command buffer.
  411.  * Add it to the currently selected history list.
  412.  */
  413.     public void
  414. cmd_accept()
  415. {
  416.     struct mlist *ml;
  417.     
  418.     /*
  419.      * Nothing to do if there is no currently selected history list.
  420.      */
  421.     if (curr_mlist == NULL)
  422.         return;
  423.     /*
  424.      * Don't save a trivial command.
  425.      */
  426.     if (strlen(cmdbuf) == 0)
  427.         return;
  428.     /*
  429.      * Don't save if a duplicate of a command which is already in the history.
  430.      * But select the one already in the history to be current.
  431.      */
  432.     for (ml = curr_mlist->next;  ml != curr_mlist;  ml = ml->next)
  433.     {
  434.         if (strcmp(ml->string, cmdbuf) == 0)
  435.             break;
  436.     }
  437.     if (ml == curr_mlist)
  438.     {
  439.         /*
  440.          * Did not find command in history.
  441.          * Save the command and put it at the end of the history list.
  442.          */
  443.         ml = (struct mlist *) ecalloc(1, sizeof(struct mlist));
  444.         ml->string = save(cmdbuf);
  445.         ml->next = curr_mlist;
  446.         ml->prev = curr_mlist->prev;
  447.         curr_mlist->prev->next = ml;
  448.         curr_mlist->prev = ml;
  449.     }
  450.     /*
  451.      * Point to the cmd just after the just-accepted command.
  452.      * Thus, an UPARROW will always retrieve the previous command.
  453.      */
  454.     curr_mlist->curr_mp = ml->next;
  455. }
  456. #endif
  457.  
  458. /*
  459.  * Try to perform a line-edit function on the command buffer,
  460.  * using a specified char as a line-editing command.
  461.  * Returns:
  462.  *    CC_PASS    The char does not invoke a line edit function.
  463.  *    CC_OK    Line edit function done.
  464.  *    CC_QUIT    The char requests the current command to be aborted.
  465.  */
  466.     static int
  467. cmd_edit(c)
  468.     int c;
  469. {
  470.     int action;
  471.     int flags;
  472.  
  473. #if TAB_COMPLETE_FILENAME
  474. #define    not_in_completion()    in_completion = 0
  475. #else
  476. #define    not_in_completion()
  477. #endif
  478.     
  479.     /*
  480.      * See if the char is indeed a line-editing command.
  481.      */
  482.     flags = 0;
  483.     if (curr_mlist == NULL)
  484.         /*
  485.          * No current history; don't accept history manipulation cmds.
  486.          */
  487.         flags |= EC_NOHISTORY;
  488.     if (curr_mlist == &mlist_search)
  489.         /*
  490.          * In a search command; don't accept file-completion cmds.
  491.          */
  492.         flags |= EC_NOCOMPLETE;
  493.  
  494.     action = editchar(c, flags);
  495.  
  496.     switch (action)
  497.     {
  498.     case EC_RIGHT:
  499.         not_in_completion();
  500.         return (cmd_right());
  501.     case EC_LEFT:
  502.         not_in_completion();
  503.         return (cmd_left());
  504.     case EC_W_RIGHT:
  505.         not_in_completion();
  506.         while (*cp != '\0' && *cp != ' ')
  507.             cmd_right();
  508.         while (*cp == ' ')
  509.             cmd_right();
  510.         return (CC_OK);
  511.     case EC_W_LEFT:
  512.         not_in_completion();
  513.         while (cp > cmdbuf && cp[-1] == ' ')
  514.             cmd_left();
  515.         while (cp > cmdbuf && cp[-1] != ' ')
  516.             cmd_left();
  517.         return (CC_OK);
  518.     case EC_HOME:
  519.         not_in_completion();
  520.         return (cmd_home());
  521.     case EC_END:
  522.         not_in_completion();
  523.         while (*cp != '\0')
  524.             cmd_right();
  525.         return (CC_OK);
  526.     case EC_INSERT:
  527.         not_in_completion();
  528.         return (CC_OK);
  529.     case EC_BACKSPACE:
  530.         not_in_completion();
  531.         return (cmd_erase());
  532.     case EC_LINEKILL:
  533.         not_in_completion();
  534.         return (cmd_kill());
  535.     case EC_W_BACKSPACE:
  536.         not_in_completion();
  537.         return (cmd_werase());
  538.     case EC_DELETE:
  539.         not_in_completion();
  540.         return (cmd_delete());
  541.     case EC_W_DELETE:
  542.         not_in_completion();
  543.         return (cmd_wdelete());
  544.     case EC_LITERAL:
  545.         literal = 1;
  546.         return (CC_OK);
  547. #if CMD_HISTORY
  548.     case EC_UP:
  549.     case EC_DOWN:
  550.         not_in_completion();
  551.         return (cmd_updown(action));
  552. #endif
  553. #if TAB_COMPLETE_FILENAME
  554.     case EC_F_COMPLETE:
  555.     case EC_B_COMPLETE:
  556.     case EC_EXPAND:
  557.         return (cmd_complete(action));
  558. #endif
  559.     default:
  560.         not_in_completion();
  561.         return (CC_PASS);
  562.     }
  563. }
  564.  
  565. /*
  566.  * Insert a char into the command buffer, at the current position.
  567.  */
  568.     static int
  569. cmd_ichar(c)
  570.     int c;
  571. {
  572.     int col;
  573.     char *p;
  574.     char *s;
  575.     
  576.     if (strlen(cmdbuf) >= sizeof(cmdbuf)-2)
  577.     {
  578.         /*
  579.          * No room in the command buffer for another char.
  580.          */
  581.         bell();
  582.         return (CC_ERROR);
  583.     }
  584.         
  585.     /*
  586.      * Remember the current cursor column and 
  587.      * move it forward the width of the char being inserted.
  588.      */
  589.     col = cmd_col;
  590.     p = prchar(c);
  591.     cmd_col += strlen(p);
  592.     if (cmd_col >= sc_width-1)
  593.     {
  594.         cmd_col -= strlen(p);
  595.         bell();
  596.         return (CC_ERROR);
  597.     }
  598.     /*
  599.      * Insert the character in the string.
  600.      * First, make room for the new char.
  601.      */
  602.     for (s = &cmdbuf[strlen(cmdbuf)];  s >= cp;  s--)
  603.         s[1] = s[0];
  604.     *cp++ = c;
  605.     /*
  606.      * Reprint the tail of the line after the inserted char.
  607.      */
  608.     clear_eol();
  609.     for (s = cp-1;  *s != '\0';  s++)
  610.     {
  611.         p = prchar(*s);
  612.         col += strlen(p);
  613.         if (col >= sc_width-1)
  614.         {
  615.             /*
  616.              * Oops.  There is no room on the screen
  617.              * for the new char.  Back up the cursor to
  618.              * just after the inserted char and erase it.
  619.              */
  620.             col -= strlen(p);
  621.             while (col > cmd_col)
  622.             {
  623.                 putbs();
  624.                 col--;
  625.             }
  626.             (void) cmd_erase();
  627.             bell();
  628.             return (CC_ERROR);
  629.         }
  630.         putstr(p);
  631.     }
  632.     /*
  633.      * Back up the cursor to just after the inserted char.
  634.      */
  635.     while (col > cmd_col)
  636.     {
  637.         putbs();
  638.         col--;
  639.     }
  640.     return (CC_OK);
  641. }
  642.  
  643. #if TAB_COMPLETE_FILENAME
  644. /*
  645.  * Insert a string into the command buffer, at the current position.
  646.  */
  647.     static int
  648. cmd_istr(str)
  649.     char *str;
  650. {
  651.     char *s;
  652.     int action;
  653.     
  654.     for (s = str;  *s != '\0';  s++)
  655.     {
  656.         action = cmd_ichar(*s);
  657.         if (action != CC_OK)
  658.         {
  659.             bell();
  660.             return (action);
  661.         }
  662.     }
  663.     return (CC_OK);
  664. }
  665.  
  666. /*
  667.  * Find the beginning and end of the "current" word.
  668.  * This is the word which the cursor (cp) is inside or at the end of.
  669.  * Return pointer to the beginning of the word and put the
  670.  * cursor at the end of the word.
  671.  */
  672.     static char *
  673. delimit_word()
  674. {
  675.     char *word;
  676.     
  677.     /*
  678.      * Move cursor to end of word.
  679.      */
  680.     if (*cp != ' ' && *cp != '\0')
  681.     {
  682.         /*
  683.          * Cursor is on a nonspace.
  684.          * Move cursor right to the next space.
  685.          */
  686.         while (*cp != ' ' && *cp != '\0')
  687.             cmd_right();
  688.     } else if (cp > cmdbuf && cp[-1] != ' ')
  689.     {
  690.         /*
  691.          * Cursor is on a space, and char to the left is a nonspace.
  692.          * We're already at the end of the word.
  693.          */
  694.         ;
  695.     } else
  696.     {
  697.         /*
  698.          * Cursor is on a space and char to the left is a space.
  699.          * Huh? There's no word here.
  700.          */
  701.         return (NULL);
  702.     }
  703.     /*
  704.      * Search backwards for beginning of the word.
  705.      */
  706.     if (cp == cmdbuf)
  707.         return (NULL);
  708.     for (word = cp-1;  word > cmdbuf;  word--)
  709.         if (word[-1] == ' ')
  710.             break;
  711.     return (word);
  712. }
  713.  
  714. /*
  715.  * Set things up to enter completion mode.
  716.  * Expand the word under the cursor into a list of filenames 
  717.  * which start with that word, and set tk_text to that list.
  718.  */
  719.     static void
  720. init_compl()
  721. {
  722.     char *word;
  723.     char c;
  724.     
  725.     /*
  726.      * Get rid of any previous tk_text.
  727.      */
  728.     if (tk_text != NULL)
  729.     {
  730.         free(tk_text);
  731.         tk_text = NULL;
  732.     }
  733.     /*
  734.      * Find the original (uncompleted) word in the command buffer.
  735.      */
  736.     word = delimit_word();
  737.     if (word == NULL)
  738.         return;
  739.     /*
  740.      * Set the insertion point to the point in the command buffer
  741.      * where the original (uncompleted) word now sits.
  742.      */
  743.     tk_ipoint = word;
  744.     /*
  745.      * Save the original (uncompleted) word
  746.      */
  747.     if (tk_original != NULL)
  748.         free(tk_original);
  749.     tk_original = (char *) ecalloc(cp-word+1, sizeof(char));
  750.     strncpy(tk_original, word, cp-word);
  751.     /*
  752.      * Get the expanded filename.
  753.      * This may result in a single filename, or
  754.      * a blank-separated list of filenames.
  755.      */
  756.     c = *cp;
  757.     *cp = '\0';
  758.     tk_text = fcomplete(word);
  759.     *cp = c;
  760. }
  761.  
  762. /*
  763.  * Return the next word in the current completion list.
  764.  */
  765.     static char *
  766. next_compl(action, prev)
  767.          int action;
  768.     char *prev;
  769. {
  770.     switch (action)
  771.     {
  772.     case EC_F_COMPLETE:
  773.         return (forw_textlist(&tk_tlist, prev));
  774.     case EC_B_COMPLETE:
  775.         return (back_textlist(&tk_tlist, prev));
  776.     default:
  777.         /* Cannot happen */
  778.         return ("?");
  779.     }
  780. }
  781.  
  782. /*
  783.  * Complete the filename before (or under) the cursor.
  784.  * cmd_complete may be called multiple times.  The global in_completion
  785.  * remembers whether this call is the first time (create the list),
  786.  * or a subsequent time (step thru the list).
  787.  */
  788.     static int
  789. cmd_complete(action)
  790.     int action;
  791. {
  792.  
  793.     if (!in_completion || action == EC_EXPAND)
  794.     {
  795.         /*
  796.          * Expand the word under the cursor and 
  797.          * use the first word in the expansion 
  798.          * (or the entire expansion if we're doing EC_EXPAND).
  799.          */
  800.         init_compl();
  801.         if (tk_text == NULL)
  802.         {
  803.             bell();
  804.             return (CC_OK);
  805.         }
  806.         if (action == EC_EXPAND)
  807.         {
  808.             /*
  809.              * Use the whole list.
  810.              */
  811.             tk_trial = tk_text;
  812.         } else
  813.         {
  814.             /*
  815.              * Use the first filename in the list.
  816.              */
  817.             in_completion = 1;
  818.             init_textlist(&tk_tlist, tk_text);
  819.             tk_trial = next_compl(action, (char*)NULL);
  820.         }
  821.     } else
  822.     {
  823.         /*
  824.          * We already have a completion list.
  825.          * Use the next/previous filename from the list.
  826.          */
  827.         tk_trial = next_compl(action, tk_trial);
  828.     }
  829.     
  830.       /*
  831.        * Remove the original word, or the previous trial completion.
  832.        */
  833.     while (cp > tk_ipoint)
  834.         (void) cmd_erase();
  835.     
  836.     if (tk_trial == NULL)
  837.     {
  838.         /*
  839.          * There are no more trial completions.
  840.          * Insert the original (uncompleted) filename.
  841.          */
  842.         in_completion = 0;
  843.         if (cmd_istr(tk_original) != CC_OK)
  844.             goto fail;
  845.     } else
  846.     {
  847.         /*
  848.          * Insert trial completion.
  849.          */
  850.         if (cmd_istr(tk_trial) != CC_OK)
  851.             goto fail;
  852.     }
  853.     
  854.     return (CC_OK);
  855.     
  856. fail:
  857.     in_completion = 0;
  858.     bell();
  859.     return (CC_OK);
  860. }
  861.  
  862. #endif /* TAB_COMPLETE_FILENAME */
  863.  
  864. /*
  865.  * Process a single character of a multi-character command, such as
  866.  * a number, or the pattern of a search command.
  867.  * Returns:
  868.  *    CC_OK        The char was accepted.
  869.  *    CC_QUIT        The char requests the command to be aborted.
  870.  *    CC_ERROR    The char could not be accepted due to an error.
  871.  */
  872.     public int
  873. cmd_char(c)
  874.     int c;
  875. {
  876.     int action;
  877.  
  878.     if (literal)
  879.     {
  880.         /*
  881.          * Insert the char, even if it is a line-editing char.
  882.          */
  883.         literal = 0;
  884.         return (cmd_ichar(c));
  885.     }
  886.         
  887.     /*
  888.      * See if it is a special line-editing character.
  889.      */
  890.     if (in_mca())
  891.     {
  892.         action = cmd_edit(c);
  893.         switch (action)
  894.         {
  895.         case CC_OK:
  896.         case CC_QUIT:
  897.             return (action);
  898.         case CC_PASS:
  899.             break;
  900.         }
  901.     }
  902.     
  903.     /*
  904.      * Insert the char into the command buffer.
  905.      */
  906.     action = cmd_ichar(c);
  907.     if (action != CC_OK)
  908.         return (action);
  909.     return (CC_OK);
  910. }
  911.  
  912. /*
  913.  * Return the number currently in the command buffer.
  914.  */
  915.     public int
  916. cmd_int()
  917. {
  918.     return (atoi(cmdbuf));
  919. }
  920.  
  921. /*
  922.  * Display a string, usually as a prompt for input into the command buffer.
  923.  */
  924.     public void
  925. cmd_putstr(s)
  926.     char *s;
  927. {
  928.     putstr(s);
  929.     cmd_col += strlen(s);
  930. }
  931.  
  932. /*
  933.  * Return a pointer to the command buffer.
  934.  */
  935.     public char *
  936. get_cmdbuf()
  937. {
  938.     return (cmdbuf);
  939. }
  940.